{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Generator"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "def printf(nums):\n",
    "    for num in nums:\n",
    "        print('num is %d'%num)\n",
    "        yield num\n",
    "def adder(nums):\n",
    "    for num in nums:\n",
    "        print('adding %d'%num)\n",
    "        if num % 2 == 0:\n",
    "            yield num + 1\n",
    "        else :\n",
    "            yield num + 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "nums = [1, 2, 3, 4,5,6,7,8]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "result = adder(printf(nums))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "num is 1\n",
      "adding 1\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "3"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "next(result)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [],
   "source": [
    "def fab(n):\n",
    "    i, a, b = 0, 0, 1\n",
    "    while i <= n:\n",
    "        yield b\n",
    "        i = i+ 1\n",
    "        a, b = b, a+b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "1\n",
      "2\n",
      "3\n",
      "5\n",
      "8\n",
      "13\n",
      "21\n",
      "34\n",
      "55\n",
      "89\n"
     ]
    }
   ],
   "source": [
    "for i in fab(10):\n",
    "    print(i)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Generator 与代码交互"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "def psychologlist():\n",
    "    print('Please tell me you problems')\n",
    "    while True:\n",
    "        answer = (yield)\n",
    "        if answer is not None:\n",
    "            if answer.endswith('?'):\n",
    "                print('do not ask your self to much questions')\n",
    "            elif 'good' in answer:\n",
    "                print(\"Ahh , that's good , go on\")\n",
    "            elif 'bad' in answer:\n",
    "                print(\"Don't be so negative\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Please tell me you problems\n"
     ]
    }
   ],
   "source": [
    "free = psychologlist()\n",
    "next(free)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "do not ask your self to much questions\n"
     ]
    }
   ],
   "source": [
    "free.send('what the hell?')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Don't be so negative\n"
     ]
    }
   ],
   "source": [
    "free.send('today is fucking bad day')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Ahh , that's good , go on\n"
     ]
    }
   ],
   "source": [
    "free.send('today is fucking good day')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Decorator\n",
    "\n",
    "- 代码更简洁，易读\n",
    "- 不能使用lambda\n",
    "- 被装饰的函数被调用时，接受单一参数，返回可调用对象（callable）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "class WithoutDecorators:\n",
    "    def some_static_method():\n",
    "        print('this is a static method')\n",
    "    # 类的静态方法\n",
    "    some_static_method = staticmethod(some_static_method)\n",
    "    def some_class_method(cls):\n",
    "        print('this is as class method')\n",
    "    some_class_method = classmethod(some_class_method)\n",
    "    \n",
    "class WithDecorators:\n",
    "    @staticmethod\n",
    "    def some_static_method():\n",
    "        print('this is a static method')\n",
    "    @classmethod\n",
    "    def some_class_method():\n",
    "        print('this is a class method')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```python\n",
    "def mydecorator(function):\n",
    "    def wrapped(*args, **kwargs):\n",
    "        # 在调用原始函数之前，做些什么\n",
    "        result = function(*args, **kwargs)\n",
    "        # 函数调用之后，做些什么\n",
    "        # 返回结果\n",
    "        return result \n",
    "    # 返回装饰后的函数\n",
    "    return wrapped\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 非参数化装饰器类\n",
    "```python\n",
    "class DecoratorAsClass:\n",
    "    def __init__(self, function):\n",
    "        self.function = function\n",
    "    def __call__(self, *args, **kwargs):\n",
    "        # 调用原始函数前\n",
    "        result = self.function(*args, **kwargs)\n",
    "        # 调用函数之后\n",
    "        # 返回结果\n",
    "        return result\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 参数化装饰器， 需要用到第二层包装\n",
    "```python\n",
    "def repeat(num=3):\n",
    "    # num 装饰器参数\n",
    "    def actual_decorator(function):\n",
    "        def wrapper(*args, **kwargs):\n",
    "            result = None\n",
    "            for _ in range(num):\n",
    "                result = function(*args, **kwargs)\n",
    "            return result\n",
    "        return wrapper\n",
    "    return actual_decorator\n",
    "\n",
    "\n",
    "@repeat(3)   # 带参数的装饰器，即便是默认参数也要带()\n",
    "def foo():\n",
    "    print('today is fucking bad day')\n",
    "    \n",
    "foo()\n",
    "\n",
    ">>>today is fucking bad day\n",
    ">>>today is fucking bad day\n",
    ">>>today is fucking bad day\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 装饰器的内省情况：\n",
    "&emsp;&emsp;使用装饰器时不保存函数的元数据(函数的注释文档和原始函数名),装饰器创建了一个新函数，并返回它，完全没有考虑被装饰函数的标识，所以在调试被装饰过的函数时会很麻烦，不能访问原始的文档字符串和函数签名。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```python\n",
    "def dummy_decorator(function):\n",
    "    def wrapped(*args, **kwargs):\n",
    "        '''包装函数的内部文档'''\n",
    "        return function(*args, **kwargs)\n",
    "    return wrapped\n",
    "\n",
    "@dummy_decorator\n",
    "def function_a():\n",
    "    '''被装饰函数的内部文档'''\n",
    "    pass\n",
    "\n",
    "\n",
    ">>>function_a.__name__\n",
    ">>>'wrapped'\n",
    ">>>function_a.__doc__\n",
    ">>>'包装函数的文档'\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 如何解决装饰器的内省问题\n",
    "\n",
    "- `form functools import wraps`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```python\n",
    "from functools import wraps\n",
    "\n",
    "def preserving_decorator(function):\n",
    "    @wraps(function)\n",
    "    def wrapped(*args, **kwargs):\n",
    "        return function(*args, **kwargs)\n",
    "    return wrapped\n",
    "\n",
    "@preserving_decorator\n",
    "def function_b():\n",
    "    '''被装饰函数的内部文档'''\n",
    "    pass\n",
    "\n",
    ">>>function_b.__name__\n",
    ">>>'function_b'\n",
    ">>>function_b.__doc__\n",
    ">>>'被装饰函数的内部文档'\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
